#ifndef __M_FMT_H__
#define __M_FMT_H__
#include "message.hpp"
#include "util.hpp"
#include "level.hpp"
#include <vector>
#include <utility>
#include <time.h>
#include <sstream>
#include <assert.h>
namespace mylog
{

	class FormatItem
	{
	public:
		using ptr = std::shared_ptr<FormatItem>;
		virtual void format(std::ostream &os, const LogMsg &msg) = 0;
	};
	class MsgFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << msg._payload;
		}
	};
	class LevelFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << LogLevel::toString(msg._level);
		}
	};
	class NameFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << msg._name;
		}
	};
	class ThreadFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << msg._tid;
		}
	};
	class TimeFormatItem : public FormatItem
	{
	private:
		std::string _timeformat;

	public:
		TimeFormatItem(const std::string &format = "%H:%M:%S") : _timeformat(format) {}
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			struct tm lt;
			localtime_r(&msg._ctime, &lt);
			char tmp[32];
			strftime(tmp, 31, _timeformat.c_str(), &lt);
			os << tmp;
		}
	};
	class CFileFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << msg._file;
		}
	};
	class CLineFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << msg._line;
		}
	};

	class TabFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << "\t";
		}
	};
	class NLineFormatItem : public FormatItem
	{
	public:
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << "\n";
		}
	};
	class OtherFormatItem : public FormatItem
	{
	private:
		std::string _str;

	public:
		OtherFormatItem(const std::string &str = ""):_str(str){}
		virtual void format(std::ostream &os, const LogMsg &msg)
		{
			os << _str;
		}
	};

	class Formatter
	{
	public:
		using ptr = std::shared_ptr<Formatter>;

		/*
				   %d 日期
				   %T 缩进
				   %t 线程id
				   %p 日志级别
				   %c 日志器名称
				   %f 文件名
				   %l 行号
				   %m 日志消息
				   %n 换行
			   */
		// 时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行
		Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
			: _pattern(pattern) { assert(parsePattern()); }

		// 进行格式化
		void format(std::ostream &os, const LogMsg &msg)
		{
			for (auto &it : _items)
				it->format(os, msg);
		}
		std::string format(const LogMsg &msg)
		{
			std::stringstream ss;
			//for (auto &it : _items)
			format(ss, msg);
			return ss.str();
		}

	private:
		bool parsePattern() // 对格式化字符串进行解析
		{					// 1.对格式化字符串进行解析 ab[%d{%H:%M:%S}][%p]%T[%c]%T
			std::vector<std::pair<std::string, std::string>> fmt_order;
			std::string key, value;
			size_t pos = 0;
			while (pos < _pattern.size())
			{
				if (_pattern[pos] != '%')
				{
					value.push_back(_pattern[pos]);
					pos++;
					continue;
				}
				// 走到这代表是% 还要判断%后面是不是%
				if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
				{
					value.push_back('%');
					pos += 2;
					continue;
				}

				// 走到这代表%后面是格式化字符 原始字符处理完毕
				if (value.empty() == false)
				{
					fmt_order.push_back(std::make_pair("", value));
					value.clear();
				}

				pos++; // 这步之后是格式化字符位置
				if (pos == _pattern.size())
				{
					std::cout << "%之后没有字符\n";
					return false;
				}
				key = _pattern[pos];
				pos++; // 这步之后是格式化字符之后的位置
				// 查大括号
				if (pos < _pattern.size() && _pattern[pos] == '{')
				{
					bool flag = false;
					pos += 1;
					while (_pattern.size() && _pattern[pos] != '}')
					{
						value.push_back(_pattern[pos]);
						pos++;
					}
					// 走到这说明没有匹配大括号 格式错误
					if (pos == _pattern.size())
					{
						std::cout << "子规则{}匹配错误！\n";
						return false;
					}
					pos += 1; // 此时位置是}位置 往后是要处理的位置
				}

				fmt_order.push_back(std::make_pair(key, value));
				value.clear();
				key.clear();
			}

			// 根据解析完的数据初始化 格式化子项数组成员
			for (auto &it : fmt_order)
				_items.push_back(createItem(it.first, it.second));
			return true;
		}

	private:
		FormatItem::ptr createItem(const std::string &key, const std::string &value)
		{
			if (key == "d")
				return FormatItem::ptr(new TimeFormatItem(value));
			if (key == "m")
				return FormatItem::ptr(new MsgFormatItem());
			if (key == "p")
				return FormatItem::ptr(new LevelFormatItem());
			if (key == "c")
				return FormatItem::ptr(new NameFormatItem());
			if (key == "t")
				return FormatItem::ptr(new ThreadFormatItem());
			if (key == "n")
				return FormatItem::ptr(new NLineFormatItem());
			if (key == "f")
				return FormatItem::ptr(new CFileFormatItem());
			if (key == "l")
				return FormatItem::ptr(new CLineFormatItem());
			if (key == "T")
				return FormatItem::ptr(new TabFormatItem());
			//return FormatItem::ptr();
			return std::make_shared<OtherFormatItem>(value);
		}
		std::string _pattern; // 格式化规则字符串
		std::vector<FormatItem::ptr> _items;
	};
}

#endif